package v2.parser.tree

import v2.parser._

/**
 * @author bweber
 * @version $Rev$, $Date$
 */

class NodeCrud  private (val startingPoint: TypedTree) extends Navigation(startingPoint) {
  def isThereAType(nameOfType: String): Boolean = {
    return Type.types.keys.contains(Symbol(nameOfType))
  }

  def hasAttr(name:String):Boolean = {
    if ( currentTree.currentNode.isInstanceOf[Slotted]) {
      currentTree.currentNode.asInstanceOf[Slotted].hasAttr(name)
    }
    else if ( currentTree.currentNode.isInstanceOf[Type]) {
      currentTree.currentNode.asInstanceOf[Type].hasAttribute(name)
    }
    else if ( currentTree.currentNode.isInstanceOf[Literal]) {
      false
    }
    false
  }
  
  def deleteAttr(name:String) = {
    if ( currentTree.currentNode.isInstanceOf[Slotted]) {
      currentTree.currentNode.asInstanceOf[Slotted].removeAttr(name)
    }
    else if ( currentTree.currentNode.isInstanceOf[Type]) {
      currentTree.currentNode.asInstanceOf[Type].removeAttribute(name)
    }
  }
  
  def clearAttr(name:String) = {
    if ( currentTree.currentNode.isInstanceOf[Slotted]) {
      currentTree.currentNode.asInstanceOf[Slotted].clearAttr(name)
    }
  }
  
  def newLiteral(id:String, str:String): Literal = {
    if (!isThereAType("str")) {
      throw new RuntimeException("No strings, thus... no literals... :(")
    }
    val literal = Literal(str,Type.typeRef("str"))
    if ( currentTree.currentNode.isInstanceOf[Slotted]) {
      if ( currentTree.currentNode.asInstanceOf[Slotted].hasAttr(id) ) {
        currentTree.currentNode.asInstanceOf[Slotted].setAttr(id,literal)
      }
      else {
        currentTree.currentNode.asInstanceOf[Slotted].addAttr(id,literal)
      }
    }
    literal
  }

  def newType(id :String, nameOfType: String): Type = {
    if (isThereAType(nameOfType)) {
      throw new RuntimeException("type " + nameOfType + " is already defined")
    }
    val typ = Type(nameOfType)
    if (currentTree.currentNode.isInstanceOf[Slotted]) {
      if ( currentTree.currentNode.asInstanceOf[Slotted].hasAttr(id)) {
        currentTree.currentNode.asInstanceOf[Slotted].setAttr(id, typ)
      }
      else {
        currentTree.currentNode.asInstanceOf[Slotted].addAttr(id, typ)
      }
    }
    typ
  }

  def newSingle(id: String, nameOfType: String): Single = {
    if (!isThereAType(nameOfType)) {
      throw new RuntimeException("No such type " + nameOfType)
    }
    val single = Single(Type(nameOfType))
    if (currentTree.currentNode.isInstanceOf[Slotted]) {
      if ( currentTree.currentNode.asInstanceOf[Slotted].hasAttr(id)) {
        currentTree.currentNode.asInstanceOf[Slotted].setAttr(id, single)
      }
      else {
        currentTree.currentNode.asInstanceOf[Slotted].addAttr(id, single)
      }
    }
    else if (currentTree.currentNode.isInstanceOf[Type]) {
      currentTree.currentNode.asInstanceOf[Type].addAttribute(id, Type.typeRef(nameOfType))
    }
    single
  }

  def newBunch(id: String, nameOfType: String): Bunch = {
    if (!isThereAType(nameOfType)) {
      throw new RuntimeException("No such type " + nameOfType)
    }
    val bunch = Bunch(Type.typeRef(nameOfType))
    if (currentTree.currentNode.isInstanceOf[Slotted]) {
      if ( currentTree.currentNode.asInstanceOf[Slotted].hasAttr(id)) {
        currentTree.currentNode.asInstanceOf[Slotted].setAttr(id, bunch)
      }
      else {
        currentTree.currentNode.asInstanceOf[Slotted].addAttr(id, bunch)
      }
    }
    // todo add bunch of type?
    bunch
  }
  
  def newAbsoluteLink(id:String, pointAt:List[String]):Link = {
    newLink(id,pointAt,true)
  }
  
  def newRelativeLink(id:String, pointAt:List[String]):Link = {
    newLink(id,pointAt,false)
  }
  
  def newLink(id:String, pointAt:List[String], isAbsolute:Boolean):Link = {
    val currentLocation = pwd
    if ( isAbsolute ) {
      absolute_cd(pointAt:_*)
    }
    else {
      relative_cd(pointAt:_*)
    }
    val link = Link(pwd) // links are always absolute
    println("trying to link " + currentLocation + " " + id + " to " + pointAt)
    if ( currentTree.currentNode.isInstanceOf[Linkable] ) {
      currentTree.currentNode.asInstanceOf[Linkable].pointToThis(link)
    }
    else {
      absolute_cd(currentLocation:_*)
      throw new RuntimeException("Target is not linkable!")
    }
    
    absolute_cd(currentLocation:_*)
    if (currentTree.currentNode.isInstanceOf[Slotted]) {
      if ( currentTree.currentNode.asInstanceOf[Slotted].hasAttr(id)) {
        currentTree.currentNode.asInstanceOf[Slotted].setAttr(id, link)
      }
      else {
        currentTree.currentNode.asInstanceOf[Slotted].addAttr(id, link)
      }
    }
    else {
      println("tree is not slotted, it is " + currentTree.currentNode)
    }
    
    link
  }

}

object NodeCrud {
  def apply(typedTree: TypedTree) = {
    new NodeCrud(typedTree)
  }

}